"""
API exceptions following SOLID principles.
"""

from typing import Any, Dict, Optional
from fastapi import HTTPException, status


class APIException(HTTPException):
    """Base API exception."""
    
    def __init__(
        self,
        status_code: int,
        detail: str,
        error_code: Optional[str] = None,
        extra_data: Optional[Dict[str, Any]] = None
    ):
        self.error_code = error_code
        self.extra_data = extra_data or {}
        
        detail_dict = {
            "message": detail,
            "error_code": error_code,
            **self.extra_data
        }
        
        super().__init__(status_code=status_code, detail=detail_dict)


class ValidationError(APIException):
    """Validation error exception."""
    
    def __init__(
        self,
        detail: str = "Validation failed",
        field_errors: Optional[Dict[str, str]] = None
    ):
        super().__init__(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail=detail,
            error_code="VALIDATION_ERROR",
            extra_data={"field_errors": field_errors or {}}
        )


class NotFoundError(APIException):
    """Resource not found exception."""
    
    def __init__(
        self,
        detail: str = "Resource not found",
        resource_type: Optional[str] = None,
        resource_id: Optional[str] = None
    ):
        extra_data = {}
        if resource_type:
            extra_data["resource_type"] = resource_type
        if resource_id:
            extra_data["resource_id"] = resource_id
        
        super().__init__(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=detail,
            error_code="NOT_FOUND",
            extra_data=extra_data
        )


class UnauthorizedError(APIException):
    """Unauthorized access exception."""
    
    def __init__(self, detail: str = "Unauthorized access"):
        super().__init__(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=detail,
            error_code="UNAUTHORIZED",
            extra_data={"headers": {"WWW-Authenticate": "Bearer"}}
        )


class ForbiddenError(APIException):
    """Forbidden access exception."""
    
    def __init__(self, detail: str = "Access forbidden"):
        super().__init__(
            status_code=status.HTTP_403_FORBIDDEN,
            detail=detail,
            error_code="FORBIDDEN"
        )


class ConflictError(APIException):
    """Resource conflict exception."""
    
    def __init__(
        self,
        detail: str = "Resource conflict",
        conflicting_field: Optional[str] = None
    ):
        extra_data = {}
        if conflicting_field:
            extra_data["conflicting_field"] = conflicting_field
        
        super().__init__(
            status_code=status.HTTP_409_CONFLICT,
            detail=detail,
            error_code="CONFLICT",
            extra_data=extra_data
        )


class RateLimitError(APIException):
    """Rate limit exceeded exception."""
    
    def __init__(
        self,
        detail: str = "Rate limit exceeded",
        retry_after: Optional[int] = None
    ):
        extra_data = {}
        if retry_after:
            extra_data["retry_after"] = retry_after
        
        super().__init__(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail=detail,
            error_code="RATE_LIMIT_EXCEEDED",
            extra_data=extra_data
        )


class InternalServerError(APIException):
    """Internal server error exception."""
    
    def __init__(
        self,
        detail: str = "Internal server error",
        error_id: Optional[str] = None
    ):
        extra_data = {}
        if error_id:
            extra_data["error_id"] = error_id
        
        super().__init__(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=detail,
            error_code="INTERNAL_SERVER_ERROR",
            extra_data=extra_data
        )


class ServiceUnavailableError(APIException):
    """Service unavailable exception."""
    
    def __init__(
        self,
        detail: str = "Service temporarily unavailable",
        retry_after: Optional[int] = None
    ):
        extra_data = {}
        if retry_after:
            extra_data["retry_after"] = retry_after
        
        super().__init__(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=detail,
            error_code="SERVICE_UNAVAILABLE",
            extra_data=extra_data
        )